PaymentSplitterFactory
Title: PaymentSplitter Factory
Author: Golem Foundation
Factory for deploying PaymentSplitter instances as minimal proxies
Uses OpenZeppelin Clones (ERC-1167) for gas-efficient deployments DEPLOYMENT PATTERN:
- Minimal proxy (EIP-1167): ~50k gas vs ~300k for full deployment
- All splitters delegate to single implementation
- Each deployment tracked for deployer FEATURES:
- Deterministic addresses via CREATE2
- Deployment tracking per deployer
- Payee name labels for identification
- Sweep function for rescue operations
Note: security-contact: [email protected]
State Variables
implementation
Address of the PaymentSplitter implementation
All deployed proxies delegate to this implementation
address public immutable implementation
owner
Factory owner authorized to sweep accidentally sent funds
Set to deployer in constructor
address public immutable owner
deployerToSplitters
Mapping of deployers to their deployed splitters
Allows tracking and enumeration of splitters per deployer
mapping(address => SplitterInfo[]) public deployerToSplitters
Functions
constructor
Deploys the factory and PaymentSplitter implementation
Deploys implementation contract used as base for all minimal proxies
constructor() ;
onlyOwner
Restricts function access to factory owner
modifier onlyOwner() ;
createPaymentSplitter
Creates a new PaymentSplitter instance with specified payees and shares
Uses CREATE2 for deterministic deployment Deploys as minimal proxy to save gas (~50k vs ~300k)
function createPaymentSplitter(address[] memory payees, string[] memory payeeNames, uint256[] memory shares)
external
returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
payees | address[] | Addresses of payees to receive payments |
payeeNames | string[] | Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx") |
shares | uint256[] | Number of shares assigned to each payee |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | paymentSplitter Address of newly created PaymentSplitter |
createPaymentSplitterWithETH
Creates a new PaymentSplitter and funds it with ETH
Uses CREATE2 for deterministic deployment with value Deploys as minimal proxy to save gas (~50k vs ~300k) Forwards msg.value to the new splitter contract
function createPaymentSplitterWithETH(address[] memory payees, string[] memory payeeNames, uint256[] memory shares)
external
payable
returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
payees | address[] | Addresses of payees to receive payments |
payeeNames | string[] | Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx") |
shares | uint256[] | Number of shares assigned to each payee |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | paymentSplitter Address of newly created PaymentSplitter |
sweep
Sweep any ETH accidentally sent to this factory
Should normally be zero since ETH forwards to clones at creation
Note: security: Only owner can sweep
function sweep(address payable recipient) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address payable | Address to receive swept ETH |
getSplittersByDeployer
Returns all payment splitters created by a specific deployer
May be expensive for deployers with many splitters
function getSplittersByDeployer(address deployer) external view returns (SplitterInfo[] memory);
Returns
| Name | Type | Description |
|---|---|---|
<none> | SplitterInfo[] | splitters Array of deployed splitters with payee info |
predictDeterministicAddress
Predicts the address of a deterministic clone for a deployer
Uses CREATE2 based on deployer address and deployment count
function predictDeterministicAddress(address deployer) external view returns (address);
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | predicted Predicted address of next deployment |
createPaymentSplitterWithSalt
Creates a new PaymentSplitter instance with an explicit salt
Uses CREATE2 with caller-provided salt for deterministic deployment This allows governance proposals to use a fixed salt, avoiding race conditions where the deployment count could change between proposal creation and execution. The final salt includes deployer, payees, shares, and caller-provided salt.
function createPaymentSplitterWithSalt(
address[] memory payees,
string[] memory payeeNames,
uint256[] memory shares,
bytes32 salt
) external returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
payees | address[] | Addresses of payees to receive payments |
payeeNames | string[] | Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx") |
shares | uint256[] | Number of shares assigned to each payee |
salt | bytes32 | Caller-provided salt for deterministic address |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | paymentSplitter Address of newly created PaymentSplitter |
createPaymentSplitterWithETHAndSalt
Creates a new PaymentSplitter with ETH and an explicit salt
Uses CREATE2 with caller-provided salt for deterministic deployment This allows governance proposals to use a fixed salt, avoiding race conditions where the deployment count could change between proposal creation and execution. Forwards msg.value to the new splitter contract.
function createPaymentSplitterWithETHAndSalt(
address[] memory payees,
string[] memory payeeNames,
uint256[] memory shares,
bytes32 salt
) external payable returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
payees | address[] | Addresses of payees to receive payments |
payeeNames | string[] | Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx") |
shares | uint256[] | Number of shares assigned to each payee |
salt | bytes32 | Caller-provided salt for deterministic address |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | paymentSplitter Address of newly created PaymentSplitter |
predictDeterministicAddressWithSalt
Predicts the address of a deterministic clone with an explicit salt
Uses CREATE2 with caller-provided salt for deterministic prediction Use this with createPaymentSplitterWithSalt to avoid race conditions in governance. Must pass the same payees and shares that will be used in createPaymentSplitterWithSalt.
function predictDeterministicAddressWithSalt(
address deployer,
address[] memory payees,
uint256[] memory shares,
bytes32 salt
) external view returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
deployer | address | Address that will call createPaymentSplitterWithSalt |
payees | address[] | Addresses of payees (must match createPaymentSplitterWithSalt call) |
shares | uint256[] | Shares for each payee (must match createPaymentSplitterWithSalt call) |
salt | bytes32 | The same salt that will be passed to createPaymentSplitterWithSalt |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | predicted Predicted address of deployment |
Events
PaymentSplitterCreated
Emitted when a new PaymentSplitter is created
event PaymentSplitterCreated(
address indexed deployer,
address indexed paymentSplitter,
address[] payees,
string[] payeeNames,
uint256[] shares
);
PaymentSplitterCreatedWithSalt
Emitted when a new PaymentSplitter is created with an explicit salt
Includes the salt for indexing, enabling off-chain tracking of salt-based deployments
event PaymentSplitterCreatedWithSalt(
address indexed deployer,
address indexed paymentSplitter,
bytes32 indexed salt,
address[] payees,
string[] payeeNames,
uint256[] shares
);
Structs
SplitterInfo
Information about a deployed payment splitter
Stored for each deployer to track their splitters
struct SplitterInfo {
/// @notice Address of the deployed splitter contract
address splitterAddress;
/// @notice Array of payee addresses
address[] payees;
/// @notice Human-readable names for each payee
/// @dev e.g., "GrantRoundOperator", "ESF", "OpEx"
string[] payeeNames;
}