Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 15 from a total of 15 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer | 24468482 | 5 days ago | IN | 0.0058452 ETH | 0.00000197 | ||||
| Transfer | 24438250 | 10 days ago | IN | 0.00944329 ETH | 0.00000276 | ||||
| Transfer | 24436749 | 10 days ago | IN | 0.00703916 ETH | 0.00000195 | ||||
| Transfer | 24435435 | 10 days ago | IN | 0.01083984 ETH | 0.00001305 | ||||
| Transfer | 24389076 | 17 days ago | IN | 0.01295887 ETH | 0.00001075 | ||||
| Transfer | 24350840 | 22 days ago | IN | 0.00766787 ETH | 0.00000423 | ||||
| Transfer | 24342281 | 23 days ago | IN | 0.01758003 ETH | 0.000024 | ||||
| Transfer | 24284457 | 31 days ago | IN | 0.04271157 ETH | 0.00004379 | ||||
| Transfer | 24248974 | 36 days ago | IN | 0.0139829 ETH | 0.00000503 | ||||
| Transfer | 24235521 | 38 days ago | IN | 0.01064832 ETH | 0.00000548 | ||||
| Transfer | 24233456 | 38 days ago | IN | 0.02591963 ETH | 0.00000901 | ||||
| Transfer | 24179021 | 46 days ago | IN | 0.01019273 ETH | 0.00000166 | ||||
| Transfer | 24159958 | 49 days ago | IN | 0.03826339 ETH | 0.00000273 | ||||
| Transfer | 24143492 | 51 days ago | IN | 0.00840931 ETH | 0.00000196 | ||||
| Transfer | 24046206 | 64 days ago | IN | 0.01632907 ETH | 0.00000116 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 24468482 | 5 days ago | 0.00467616 ETH | ||||
| Transfer | 24468482 | 5 days ago | 0.00116904 ETH | ||||
| Transfer | 24438250 | 10 days ago | 0.00755463 ETH | ||||
| Transfer | 24438250 | 10 days ago | 0.00188865 ETH | ||||
| Transfer | 24436749 | 10 days ago | 0.00563133 ETH | ||||
| Transfer | 24436749 | 10 days ago | 0.00140783 ETH | ||||
| Transfer | 24435435 | 10 days ago | 0.00867187 ETH | ||||
| Transfer | 24435435 | 10 days ago | 0.00216796 ETH | ||||
| Transfer | 24389076 | 17 days ago | 0.0103671 ETH | ||||
| Transfer | 24389076 | 17 days ago | 0.00259177 ETH | ||||
| Transfer | 24350840 | 22 days ago | 0.00613429 ETH | ||||
| Transfer | 24350840 | 22 days ago | 0.00153357 ETH | ||||
| Transfer | 24342281 | 23 days ago | 0.01406402 ETH | ||||
| Transfer | 24342281 | 23 days ago | 0.003516 ETH | ||||
| Transfer | 24284457 | 31 days ago | 0.03416926 ETH | ||||
| Transfer | 24284457 | 31 days ago | 0.00854231 ETH | ||||
| Transfer | 24248974 | 36 days ago | 0.01118632 ETH | ||||
| Transfer | 24248974 | 36 days ago | 0.00279658 ETH | ||||
| Transfer | 24235521 | 38 days ago | 0.00851866 ETH | ||||
| Transfer | 24235521 | 38 days ago | 0.00212966 ETH | ||||
| Transfer | 24233456 | 38 days ago | 0.02073571 ETH | ||||
| Transfer | 24233456 | 38 days ago | 0.00518392 ETH | ||||
| Transfer | 24179021 | 46 days ago | 0.00815418 ETH | ||||
| Transfer | 24179021 | 46 days ago | 0.00203854 ETH | ||||
| Transfer | 24159958 | 49 days ago | 0.03826339 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x2f0bb99ffc519a37c3ba3d128e51b29a70c64e84
Contract Name:
Splitter
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
// SPDX-FileCopyrightText: 2024 Kiln <contact@kiln.fi>
//
// ██╗ ██╗██╗██╗ ███╗ ██╗
// ██║ ██╔╝██║██║ ████╗ ██║
// █████╔╝ ██║██║ ██╔██╗ ██║
// ██╔═██╗ ██║██║ ██║╚██╗██║
// ██║ ██╗██║███████╗██║ ╚████║
// ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝
//
pragma solidity 0.8.22;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Operator} from "./Operator.sol";
/// @title Splitter
/// @notice The Splitter contract is used to directly split any funds it receives between its owner and linked Operator
contract Splitter {
/// @notice The Operator contract that will receive a portion of the funds
Operator public operator;
/// @notice The owner of the contract
address public owner;
/// @notice The maximum value for a percentage in bps
uint256 internal constant MAX_BPS = 10000;
/// @notice Emitted when the contract is configured
/// @param operator The Operator contract that will receive a portion of the funds
/// @param owner The owner of the contract
event Configured(address indexed operator, address indexed owner);
/// @notice Emitted when the received funds are split
/// @param operator The operator of the contract
/// @param recipient The recipient of the funds
/// @param operatorAmount The amount of funds that were sent to the operator
/// @param recipientAmount The amount of funds that were sent to the recipient
event Split(address indexed operator, address indexed recipient, uint256 operatorAmount, uint256 recipientAmount);
/// @notice Emitted when the transfer to the owner fails and we explicitly do not revert
/// @param errorData The error data returned by the transfer
event OwnerTransferFailureCaught(bytes errorData);
/// @notice Thrown when the contract is already initialized
error AlreadyInitialized();
/// @notice Thrown when the sender is not the owner
/// @param sender The sender of the transaction
error Unauthorized(address sender);
/// @notice Thrown when the transfer to the owner fails
/// @param recipient The recipient of the transfer
/// @param errorData The error data returned by the transfer
error OwnerTransferFailed(address recipient, bytes errorData);
/// @notice Thrown when the transfer to the operator fails
/// @param errorData The error data returned by the transfer
error OperatorTransferFailed(bytes errorData);
/// @notice Thrown when the provided address is zero
error InvalidZeroAddress();
/// @notice Thrown when the provided operator address is not a contract
error InvalidOperatorAddress();
/// @notice Thrown when the initialization is performed more than once
modifier uninitialized() {
if (address(operator) != address(0) || address(owner) != address(0)) {
revert AlreadyInitialized();
}
_;
}
constructor() {
operator = Operator(payable(address(uint160(uint256(bytes32("implem initialized"))))));
}
/// @notice The receive function is used to receive ETH
receive() external payable {
_split(owner, false);
}
/// @notice The fallback function is used to receive ETH when there is additional calldata
fallback() external payable {
_split(owner, false);
}
/// @notice Initializes the contract
/// @param _operator The Operator contract that will receive a portion of the funds
/// @param _owner The owner of the contract
function init(Operator _operator, address _owner) external uninitialized {
if (address(_operator) == address(0) || address(_owner) == address(0)) {
revert InvalidZeroAddress();
}
if (address(_operator).code.length == 0) {
revert InvalidOperatorAddress();
}
operator = _operator;
owner = _owner;
emit Configured(address(_operator), _owner);
}
/// @notice Claims the funds from the contract
function claim() external {
_split(owner, true);
}
/// @notice Claims the funds from the contract and sends them to the provided recipient
/// @param recipient The recipient of the funds
function claim(address recipient) external {
if (msg.sender != owner) {
revert Unauthorized(msg.sender);
}
_split(recipient, true);
}
/// @notice Claims the funds from the contract and sends them to the provided recipients
/// @param recipient The recipient that receives the funds for the owner
function _split(address recipient, bool revertOnTransferFail) internal {
uint256 balance = address(this).balance;
if (balance == 0) {
return;
}
uint256 operatorFee = operator.operatorFee();
uint256 operatorAmount = operatorFee > 0 ? Math.mulDiv(balance, operatorFee, MAX_BPS) : 0;
uint256 ownerAmount = balance - operatorAmount;
(bool success, bytes memory rdata) = recipient.call{value: ownerAmount}("");
if (!success) {
if (revertOnTransferFail) {
revert OwnerTransferFailed(recipient, rdata);
} else {
emit OwnerTransferFailureCaught(rdata);
return;
}
}
(success, rdata) = address(operator).call{value: operatorAmount}("");
if (!success) {
revert OperatorTransferFailed(rdata);
}
emit Split(address(operator), recipient, operatorAmount, ownerAmount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: BUSL-1.1
// SPDX-FileCopyrightText: 2024 Kiln <contact@kiln.fi>
//
// ██╗ ██╗██╗██╗ ███╗ ██╗
// ██║ ██╔╝██║██║ ████╗ ██║
// █████╔╝ ██║██║ ██╔██╗ ██║
// ██╔═██╗ ██║██║ ██║╚██╗██║
// ██║ ██╗██║███████╗██║ ╚████║
// ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝
//
pragma solidity 0.8.22;
import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/// @title Operator
/// @notice The Operator contract is used to store a commission distribution scheme for one or several Splitter instances
/// @notice It stores a list of recipients alongside their respective percentages, and a fee that is taken on each Splitter
/// @notice It then handles the dispatching of the commission between the configured recipient
contract Operator is Ownable2Step {
/// @notice The fee that is taken on each Splitter
uint256 public operatorFee;
/// @notice The maximum fee that can be configured on the Operator
// solhint-disable-next-line immutable-vars-naming
uint256 public immutable maximumOperatorFee;
/// @notice The list of recipients
address[] public recipients;
/// @notice The list of percentages for each recipient
uint256[] public percents;
/// @notice The name of the operator
string public name;
/// @notice The maximum value for a percentage in bps
uint256 internal constant MAX_BPS = 10000;
/// @notice Emitted when the recipients are updated
/// @param recipients The new list of recipients
/// @param percentsBps The new list of percentages
event UpdatedRecipients(address[] recipients, uint256[] percentsBps);
/// @notice Emitted when the operator fee is updated
/// @param operatorFee The new operator fee
event UpdatedOperatorFee(uint256 operatorFee);
/// @notice Emitted when the operator name is updated
/// @param name The new operator name
event UpdatedOperatorName(string name);
/// @notice Emitted when the maximum operator fee is updated
/// @param maximumOperatorFee The new maximum operator fee
event UpdatedMaximumOperatorFee(uint256 maximumOperatorFee);
/// @notice Emitted when the commission is claimed
/// @param amount The amount that was claimed
event Claimed(uint256 amount);
/// @notice Thrown when the provided recipient list is empty
error NoRecipients();
/// @notice Thrown when the provided recipient is null
error ZeroAddress();
/// @notice Thrown when the provided percent value is zero
error ZeroPercentBps();
/// @notice Thrown when the transfer to a recipient fails
/// @param recipient The recipient that failed to receive the funds
/// @param errorData The error data returned by the transfer
error RecipientTransferFailed(address recipient, bytes errorData);
/// @notice Thrown when the provided recipient list is empty
error EmptyRecipientArguments();
/// @notice Thrown when the provided recipient list and percentage list have different lengths
error InvalidArgumentLengths();
/// @notice Thrown when the provided percentages do not sum up to 10000
error InvalidPercentSum();
/// @notice Thrown when the provided fee is invalid
/// @param feeBps The provided fee
error InvalidFeeBps(uint256 feeBps);
/// @notice Thrown when the provided name is empty
error InvalidEmptyString();
/// @notice Thrown when the provided recipients are not sorted
error InvalidUnsortedRecipients();
/// @param _owner The owner of the contract
/// @param _operatorFee The fee that is taken on each Splitter
/// @param _recipients The list of recipients, sorted in ascending order without duplicates
/// @param _percents The list of percentages for each recipient
constructor(
address _owner,
string memory _name,
uint256 _operatorFee,
uint256 _maximumOperatorFee,
address[] memory _recipients,
uint256[] memory _percents
) Ownable(_owner) {
if (_maximumOperatorFee > MAX_BPS) {
revert InvalidFeeBps(_maximumOperatorFee);
}
maximumOperatorFee = _maximumOperatorFee;
emit UpdatedMaximumOperatorFee(_maximumOperatorFee);
_setOperatorFee(_operatorFee);
_setRecipients(_recipients, _percents);
_setName(_name);
}
/// @notice The receive function is used to receive ETH
receive() external payable {
// do nothing
}
/// @notice The fallback function is used to receive ETH when there is additional calldata
fallback() external payable {
// do nothing
}
/// @notice Changes the operator fee
/// @param _operatorFee The new operator fee
function setOperatorFee(uint256 _operatorFee) external onlyOwner {
_setOperatorFee(_operatorFee);
}
/// @notice Changes the recipients and their respective percentages
/// @param _recipients The new list of recipients, sorted in ascending order without duplicates
/// @param _percents The new list of percentages
function setRecipients(address[] calldata _recipients, uint256[] calldata _percents) external onlyOwner {
_setRecipients(_recipients, _percents);
}
/// @notice Changes the operator name
/// @param _name The new operator name
function setName(string calldata _name) external onlyOwner {
_setName(_name);
}
/// @notice Claims the commission for all the recipients
function claim() external {
uint256 balance = address(this).balance;
uint256 totalSent = 0;
for (uint256 i = 0; i < recipients.length - 1;) {
uint256 value = Math.mulDiv(balance, percents[i], MAX_BPS);
(bool success, bytes memory rdata) = recipients[i].call{value: value}("");
if (!success) {
revert RecipientTransferFailed(recipients[i], rdata);
}
totalSent += value;
unchecked {
++i;
}
}
{
(bool success, bytes memory rdata) = recipients[recipients.length - 1].call{value: balance - totalSent}("");
if (!success) {
revert RecipientTransferFailed(recipients[recipients.length - 1], rdata);
}
}
emit Claimed(balance);
}
/// @notice Internal utility function to set the operator fee
/// @param _operatorFee The new operator fee
function _setOperatorFee(uint256 _operatorFee) internal {
if (_operatorFee > maximumOperatorFee) {
revert InvalidFeeBps(_operatorFee);
}
operatorFee = _operatorFee;
emit UpdatedOperatorFee(_operatorFee);
}
/// @notice Internal utility function to set the recipients and their respective percentages
/// @param _recipients The new list of recipients, sorted in ascending order without duplicates
/// @param _percentsBps The new list of percentages
function _setRecipients(address[] memory _recipients, uint256[] memory _percentsBps) internal {
uint256 recipientsLength = _recipients.length;
if (recipientsLength == 0) {
revert EmptyRecipientArguments();
}
if (recipientsLength != _percentsBps.length) {
revert InvalidArgumentLengths();
}
uint256 totalPercentsBps = 0;
for (uint256 i = 0; i < recipientsLength; ++i) {
totalPercentsBps += _percentsBps[i];
if (i > 0 && uint160(_recipients[i]) <= uint160(_recipients[i - 1])) {
revert InvalidUnsortedRecipients();
}
if (_recipients[i] == address(0)) {
revert ZeroAddress();
}
if (_percentsBps[i] == 0) {
revert ZeroPercentBps();
}
}
if (totalPercentsBps != MAX_BPS) {
revert InvalidPercentSum();
}
recipients = _recipients;
percents = _percentsBps;
emit UpdatedRecipients(_recipients, _percentsBps);
}
/// @notice Internal utility function to set the operator name
/// @param _name The new operator name
function _setName(string memory _name) internal {
if (bytes(_name).length == 0) {
revert InvalidEmptyString();
}
name = _name;
emit UpdatedOperatorName(_name);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"vulcan/=lib/vulcan/src/",
"deploy.sol/=lib/deploy.sol/src/",
"solmate/=lib/deploy.sol/lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidOperatorAddress","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"OperatorTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"OwnerTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Configured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"OwnerTransferFailureCaught","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"operatorAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"recipientAmount","type":"uint256"}],"name":"Split","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Operator","name":"_operator","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"contract Operator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]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
[ 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.