Skip to main content

PaymentSplitter

Git Source

Inherits: Initializable, Context

Title: PaymentSplitter

Author: OpenZeppelin; adapted by Golem Foundation

Splits ETH and ERC20 token payments proportionally among payees based on shares

Modified from OpenZeppelin to use initializable pattern instead of constructor. Payments split in proportion to number of shares held by each account. Pull payment model where payees call release() to claim their share. Not compatible with rebasing or fee-on-transfer tokens.

Notes:

Quick Start — What Matters Most

The PaymentSplitter distributes yield shares proportionally to configured recipients using a pull-payment model.

Key functions to understand:

  • release — Payee claims their share (pull payment model)
  • shares — Check a payee's share allocation
  • released — Check how much a payee has already claimed

State Variables

_totalShares

Total shares across all payees

Sum of all individual payee shares. Used as denominator in distribution calculations

uint256 private _totalShares

_totalReleased

Total ETH released to all payees

Cumulative amount of ETH paid out. Used to calculate pending payments

uint256 private _totalReleased

_shares

Mapping of payee addresses to their share allocation

Set once during initialize(). Immutable after initialization

mapping(address => uint256) private _shares

_released

Mapping of payee addresses to ETH already released to them

Tracks cumulative ETH paid to each payee

mapping(address => uint256) private _released

_payees

Array of all payee addresses

Used for enumeration. Set during initialize(). Immutable

address[] private _payees

_erc20TotalReleased

Mapping of ERC20 tokens to total amount released

Tracks cumulative amount of each token paid out

mapping(IERC20 => uint256) private _erc20TotalReleased

_erc20Released

Nested mapping of tokens to payees to amounts released

Tracks cumulative amount of each token paid to each payee

mapping(IERC20 => mapping(address => uint256)) private _erc20Released

Functions

constructor

Constructor disables direct initialization

Prevents using this contract directly - must be used via proxy pattern Disables initializers so only proxy instances can be initialized

constructor() payable;

receive

Receives ETH payments and emits event

WARNING: Events are not fully reliable - ETH can be received without triggering this (e.g., via selfdestruct). Event reliability doesn't affect actual payment splitting See Solidity docs on fallback functions for details

receive() external payable virtual;

initialize

Initializes the payment splitter with payees and their shares

CRITICAL: Can only be called ONCE (enforced by initializer modifier) Sets immutable payee list and share allocations VALIDATION:

  • Arrays must have same length
  • Arrays must be non-empty
  • All payee addresses must be non-zero
  • All shares must be > 0
  • No duplicate payees allowed EXAMPLE: payees = [alice, bob, charlie] shares = [50, 30, 20] Result: Alice gets 50%, Bob gets 30%, Charlie gets 20%

Notes:

  • security: Can only be called once via initializer

  • security: Payee list is immutable after initialization

function initialize(address[] memory payees, uint256[] memory shares_) public payable initializer;

Parameters

NameTypeDescription
payeesaddress[]Array of payee addresses (cannot be zero addresses)
shares_uint256[]Array of proportional allocation shares for each payee (unitless, must all be > 0)

totalShares

Returns the total shares across all payees

Used as denominator in payment calculations

function totalShares() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256total Sum of all payee proportional allocation shares (unitless)

totalReleased

Returns total ETH released to all payees

Cumulative amount paid out since deployment

function totalReleased() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256total Total ETH released in wei

totalReleased

Returns total amount of an ERC20 token released to all payees

Cumulative amount of specific token paid out

function totalReleased(IERC20 token) public view returns (uint256);

Parameters

NameTypeDescription
tokenIERC20Address of the ERC20 token contract

Returns

NameTypeDescription
<none>uint256total Total tokens released

shares

Returns the share allocation for a payee

Share count, not percentage. Percentage = shares / totalShares

function shares(address account) public view returns (uint256);

Parameters

NameTypeDescription
accountaddressAddress of the payee

Returns

NameTypeDescription
<none>uint256shares Number of proportional allocation shares assigned to payee (unitless)

released

Returns ETH already released to a payee

Cumulative amount paid to this payee

function released(address account) public view returns (uint256);

Parameters

NameTypeDescription
accountaddressAddress of the payee

Returns

NameTypeDescription
<none>uint256amount ETH released in wei

released

Returns amount of an ERC20 token already released to a payee

Cumulative amount of specific token paid to this payee

function released(IERC20 token, address account) public view returns (uint256);

Parameters

NameTypeDescription
tokenIERC20Address of the ERC20 token contract
accountaddressAddress of the payee

Returns

NameTypeDescription
<none>uint256amount Tokens released

payee

Returns the payee address at a specific index

Used for enumerating all payees

function payee(uint256 index) public view returns (address);

Parameters

NameTypeDescription
indexuint256Index in the payees array (0 to payees.length - 1)

Returns

NameTypeDescription
<none>addresspayee Payee address at the index

releasable

Returns amount of ETH claimable by a payee

Formula: (totalReceived * payeeShares / totalShares) - alreadyReleased totalReceived = current balance + total released

function releasable(address account) public view returns (uint256);

Parameters

NameTypeDescription
accountaddressAddress of the payee

Returns

NameTypeDescription
<none>uint256amount Claimable ETH in wei

releasable

Returns amount of ERC20 tokens claimable by a payee

Formula: (totalReceived * payeeShares / totalShares) - alreadyReleased totalReceived = current balance + total released

function releasable(IERC20 token, address account) public view returns (uint256);

Parameters

NameTypeDescription
tokenIERC20Address of the ERC20 token contract
accountaddressAddress of the payee

Returns

NameTypeDescription
<none>uint256amount Claimable tokens

release

Releases owed ETH to a payee

Pull payment: payee calls this to claim their share of accumulated ETH CALCULATION: payment = (totalReceived * payeeShares / totalShares) - alreadyReleased REQUIREMENTS:

  • Account must have shares > 0
  • Payment must be > 0 EFFECTS:
  • Updates _totalReleased and _released[account]
  • Transfers ETH to account
  • Emits PaymentReleased event

Note: security: Uses OpenZeppelin's Address.sendValue for safe ETH transfer

function release(address payable account) public virtual;

Parameters

NameTypeDescription
accountaddress payableAddress of the payee to release payment to

release

Releases owed ERC20 tokens to a payee

Pull payment: payee calls this to claim their share of accumulated tokens CALCULATION: payment = (totalReceived * payeeShares / totalShares) - alreadyReleased REQUIREMENTS:

  • Account must have shares > 0
  • Payment must be > 0 COMPATIBILITY WARNING:
  • Not compatible with rebasing tokens
  • Not compatible with fee-on-transfer tokens
  • Test with specific token before production use

Note: security: Uses SafeERC20 for safe token transfers

function release(IERC20 token, address account) public virtual;

Parameters

NameTypeDescription
tokenIERC20Address of the ERC20 token contract
accountaddressAddress of the payee to release payment to

_pendingPayment

Calculates pending payment for a payee

function _pendingPayment(address account, uint256 totalReceived, uint256 alreadyReleased)
private
view
returns (uint256);

Parameters

NameTypeDescription
accountaddressPayee address
totalReceiveduint256Total received (balance + released)
alreadyReleaseduint256Amount already paid to this payee

Returns

NameTypeDescription
<none>uint256payment Amount currently owed to payee

_addPayee

function _addPayee(address account, uint256 shares_) private;

Parameters

NameTypeDescription
accountaddressPayee address (cannot be zero)
shares_uint256Number of shares to assign (must be > 0)

Events

PayeeAdded

Emitted when a new payee is added during initialization

event PayeeAdded(address account, uint256 shares);

Parameters

NameTypeDescription
accountaddressAddress of the payee added
sharesuint256Number of proportional allocation shares assigned to the payee (unitless)

PaymentReleased

Emitted when ETH is released to a payee

event PaymentReleased(address to, uint256 amount);

Parameters

NameTypeDescription
toaddressAddress receiving the payment
amountuint256Amount of ETH released in wei

ERC20PaymentReleased

Emitted when ERC20 tokens are released to a payee

event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount);

Parameters

NameTypeDescription
tokenIERC20ERC20 token being released
toaddressAddress receiving the payment
amountuint256Amount of tokens released

PaymentReceived

Emitted when ETH is received by the contract

event PaymentReceived(address from, uint256 amount);

Parameters

NameTypeDescription
fromaddressAddress sending the ETH
amountuint256Amount of ETH received in wei