Skip to main content

PaymentSplitterFactory

Git Source

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

NameTypeDescription
payeesaddress[]Addresses of payees to receive payments
payeeNamesstring[]Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx")
sharesuint256[]Number of shares assigned to each payee

Returns

NameTypeDescription
<none>addresspaymentSplitter 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

NameTypeDescription
payeesaddress[]Addresses of payees to receive payments
payeeNamesstring[]Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx")
sharesuint256[]Number of shares assigned to each payee

Returns

NameTypeDescription
<none>addresspaymentSplitter 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

NameTypeDescription
recipientaddress payableAddress 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

NameTypeDescription
<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

NameTypeDescription
<none>addresspredicted 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

NameTypeDescription
payeesaddress[]Addresses of payees to receive payments
payeeNamesstring[]Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx")
sharesuint256[]Number of shares assigned to each payee
saltbytes32Caller-provided salt for deterministic address

Returns

NameTypeDescription
<none>addresspaymentSplitter 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

NameTypeDescription
payeesaddress[]Addresses of payees to receive payments
payeeNamesstring[]Names for each payee (e.g., "GrantRoundOperator", "ESF", "OpEx")
sharesuint256[]Number of shares assigned to each payee
saltbytes32Caller-provided salt for deterministic address

Returns

NameTypeDescription
<none>addresspaymentSplitter 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

NameTypeDescription
deployeraddressAddress that will call createPaymentSplitterWithSalt
payeesaddress[]Addresses of payees (must match createPaymentSplitterWithSalt call)
sharesuint256[]Shares for each payee (must match createPaymentSplitterWithSalt call)
saltbytes32The same salt that will be passed to createPaymentSplitterWithSalt

Returns

NameTypeDescription
<none>addresspredicted 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;
}