Skip to main content


Contract: JBSingleTokenPaymentTerminalStore​‌

Distributes payouts for a project with the distribution limit of its current funding cycle.

Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.

Anyone can distribute payouts on a project's behalf. The project can preconfigure a wildcard split that is used to send funds to msg.sender. This can be used to incentivize calling this function.

All funds distributed outside of this contract or any feeless terminals incure the protocol fee.


function _distributePayoutsOf(
uint256 _projectId,
uint256 _amount,
uint256 _currency,
uint256 _minReturnedTokens,
string calldata _memo
) private returns (uint256 netLeftoverDistributionAmount) { ... }
  • Arguments:
    • _projectId is the ID of the project having its payouts distributed.
    • _amount is the amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.
    • _currency is the expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.
    • _minReturnedTokens is the minimum number of terminal tokens that the _amount should be valued at in terms of this terminal's currency, as a fixed point number with the same number of decimals as this terminal.
    • _memo is a memo to pass along to the emitted event.
  • The function is private to this contract.
  • The function returns the amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.


  1. Record the distribution.

    // Record the distribution.
    (JBFundingCycle memory _fundingCycle, uint256 _distributedAmount) = store.recordDistributionFor(

    Internal references:

    External references:

  2. Make sure the distributed amount is at least as much as the minimum expected amount.

    // The amount being distributed must be at least as much as was expected.
    if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();
  3. Get a reference to the project's owner. The owner will be allocated any funds leftover once splits are settled.

    // Get a reference to the project owner, which will receive tokens from paying the platform fee
    // and receive any extra distributable funds not allocated to payout splits.
    address payable _projectOwner = payable(projects.ownerOf(_projectId));

    External references:

  4. The following scoped block is a bit of a hack to prevent a "Stack too deep" error. Define a few variables outside of the scope that'll be set within the scope but later referenced again outside.

    // Define variables that will be needed outside the scoped section below.
    // Keep a reference to the fee amount that was paid.
    uint256 _fee;

    // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.
    { ... }
    1. Get a reference to the discount that'll be used when applying the fee. If the fee is 0, set the discount to be 100% to simplify subsequent calculations. No fee is the same as a full discount.

      // Get the amount of discount that should be applied to any fees taken.
      // If the fee is zero or if the fee is being used by an address that doesn't incur fees, set the discount to 100% for convenience.
      uint256 _feeDiscount = fee == 0
      ? JBConstants.MAX_FEE_DISCOUNT
      : _currentFeeDiscount(_projectId);

      Library references:

      Internal references:

    2. Get a reference to the amount of distributed funds from which fees should be taken, and the amount leftover after distributing splits.

      // The amount distributed that is eligible for incurring fees.
      uint256 _feeEligibleDistributionAmount;

      // The amount leftover after distributing to the splits.
      uint256 _leftoverDistributionAmount;d
    3. Distribute the amount to all payout splits. Get a reference to any leftover amount, and all amounts sent to splits from which fees should be taken.

      // Payout to splits and get a reference to the leftover amount after all splits have been paid.
      // Also get a reference to the amount that was distributed to splits from which fees should be taken.
      (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(

      Internal references:

    4. Add the leftover distribution amount to the amount from which fees should be taken since those funds will be leaving the ecosystem to the project owner's address.

      if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {
      // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.
      unchecked {
      _feeEligibleDistributionAmount += _leftoverDistributionAmount;
    5. Take the fee if needed.

      // Take the fee.
      _fee = _feeEligibleDistributionAmount != 0
      ? _takeFeeFrom(
      : 0;

      Library references:

      Internal references:

    6. Calculate what the net value of the leftover distribution will be, and send it.

      // Transfer any remaining balance to the project owner and update returned leftover accordingly.
      if (_leftoverDistributionAmount != 0) {
      // Subtract the fee from the net leftover amount.
      netLeftoverDistributionAmount =
      _leftoverDistributionAmount -
      _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);

      // Transfer the amount to the project owner.
      _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);

      Internal references:

      Virtual references:

  5. Emit a DistributePayouts event with the relevant parameters.

    emit DistributePayouts(

    Event references: