JBController

Created Diff never expires
247 removals
Words removed976
Total words4366
Words removed (%)22.35
1061 lines
60 additions
Words added210
Total words3600
Words added (%)5.83
878 lines
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
pragma solidity ^0.8.16;


import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
import '@openzeppelin/contracts/utils/math/SafeCast.sol';
import '@openzeppelin/contracts/utils/math/SafeCast.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import './abstract/JBOperatable.sol';
import './abstract/JBOperatable.sol';
import './interfaces/IJBController.sol';
import './interfaces/IJBController3_1.sol';
import './interfaces/IJBMigratable.sol';
import './interfaces/IJBMigratable.sol';
import './interfaces/IJBOperatorStore.sol';
import './interfaces/IJBOperatorStore.sol';
import './interfaces/IJBPaymentTerminal.sol';
import './interfaces/IJBPaymentTerminal.sol';
import './interfaces/IJBProjects.sol';
import './interfaces/IJBProjects.sol';
import './libraries/JBConstants.sol';
import './libraries/JBConstants.sol';
import './libraries/JBFundingCycleMetadataResolver.sol';
import './libraries/JBFundingCycleMetadataResolver.sol';
import './libraries/JBOperations.sol';
import './libraries/JBOperations.sol';
import './libraries/JBSplitsGroups.sol';
import './libraries/JBSplitsGroups.sol';


/**
/**
@notice
@notice
Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.
Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.


@dev
@dev
Adheres to -
Adheres to -
IJBController: General interface for the generic controller methods in this contract that interacts with funding cycles and tokens according to the protocol's rules.
IJBController3_1: General interface for the generic controller methods in this contract that interacts with funding cycles and tokens according to the protocol's rules.
IJBMigratable: Allows migrating to this contract, with a hook called to prepare for the migration.
IJBMigratable: Allows migrating to this contract, with a hook called to prepare for the migration.


@dev
@dev
Inherits from -
Inherits from -
JBOperatable: Several functions in this contract can only be accessed by a project owner, or an address that has been preconfifigured to be an operator of the project.
JBOperatable: Several functions in this contract can only be accessed by a project owner, or an address that has been preconfifigured to be an operator of the project.
ERC165: Introspection on interface adherance.
ERC165: Introspection on interface adherance.

@dev
This Controller has the same functionality as JBController3_1, except it is not backwards compatible with the original IJBController view methods.
*/
*/
contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {
contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {
// A library that parses the packed funding cycle metadata into a more friendly format.
// A library that parses the packed funding cycle metadata into a more friendly format.
using JBFundingCycleMetadataResolver for JBFundingCycle;
using JBFundingCycleMetadataResolver for JBFundingCycle;


//*********************************************************************//
//*********************************************************************//
// --------------------------- custom errors ------------------------- //
// --------------------------- custom errors ------------------------- //
//*********************************************************************//
//*********************************************************************//

error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();
error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();
error CANT_MIGRATE_TO_CURRENT_CONTROLLER();
error CANT_MIGRATE_TO_CURRENT_CONTROLLER();
error FUNDING_CYCLE_ALREADY_LAUNCHED();
error FUNDING_CYCLE_ALREADY_LAUNCHED();
error INVALID_BALLOT_REDEMPTION_RATE();
error INVALID_BALLOT_REDEMPTION_RATE();
error INVALID_DISTRIBUTION_LIMIT();
error INVALID_DISTRIBUTION_LIMIT_CURRENCY();
error INVALID_OVERFLOW_ALLOWANCE();
error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();
error INVALID_REDEMPTION_RATE();
error INVALID_REDEMPTION_RATE();
error INVALID_RESERVED_RATE();
error INVALID_RESERVED_RATE();
error MIGRATION_NOT_ALLOWED();
error MIGRATION_NOT_ALLOWED();
error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();
error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();
error NO_BURNABLE_TOKENS();
error NO_BURNABLE_TOKENS();
error NOT_CURRENT_CONTROLLER();
error NOT_CURRENT_CONTROLLER();
error OVERFLOW_ALERT();
error OVERFLOW_ALERT();
error ZERO_TOKENS_TO_MINT();
error ZERO_TOKENS_TO_MINT();


//*********************************************************************//
//*********************************************************************//
// --------------------- internal stored properties ------------------ //
// --------------------- internal stored properties ------------------ //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
The difference between the processed token tracker of a project and the project's token's total supply is the amount of tokens that still need to have reserves minted against them.

_projectId The ID of the project to get the tracker of.
*/
mapping(uint256 => int256) internal _processedTokenTrackerOf;

/**
@notice
Data regarding the distribution limit of a project during a configuration.
Data regarding the distribution limit of a project during a configuration.


@dev
@dev
bits 0-231: The amount of token that a project can distribute per funding cycle.
bits 0-231: The amount of token that a project can distribute per funding cycle.


@dev
@dev
bits 232-255: The currency of amount that a project can distribute.
bits 232-255: The currency of amount that a project can distribute.


_projectId The ID of the project to get the packed distribution limit data of.
_projectId The ID of the project to get the packed distribution limit data of.
_configuration The configuration during which the packed distribution limit data applies.
_configuration The configuration during which the packed distribution limit data applies.
_terminal The terminal from which distributions are being limited.
_terminal The terminal from which distributions are being limited.
_token The token for which distributions are being limited.
_token The token for which distributions are being limited.
*/
*/
mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))
mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))
internal _packedDistributionLimitDataOf;
internal _packedDistributionLimitDataOf;


/**
/**
@notice
@notice
Data regarding the overflow allowance of a project during a configuration.
Data regarding the overflow allowance of a project during a configuration.


@dev
@dev
bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.
bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.


@dev
@dev
bits 232-255: The currency of the amount of overflow that a project is allowed to tap.
bits 232-255: The currency of the amount of overflow that a project is allowed to tap.


_projectId The ID of the project to get the packed overflow allowance data of.
_projectId The ID of the project to get the packed overflow allowance data of.
_configuration The configuration during which the packed overflow allowance data applies.
_configuration The configuration during which the packed overflow allowance data applies.
_terminal The terminal managing the overflow.
_terminal The terminal managing the overflow.
_token The token for which overflow is being allowed.
_token The token for which overflow is being allowed.
*/
*/
mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))
mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))
internal _packedOverflowAllowanceDataOf;
internal _packedOverflowAllowanceDataOf;


//*********************************************************************//
//*********************************************************************//
// --------------- public immutable stored properties ---------------- //
// --------------- public immutable stored properties ---------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
Mints ERC-721's that represent project ownership.
Mints ERC-721's that represent project ownership.
*/
*/
IJBProjects public immutable override projects;
IJBProjects public immutable override projects;


/**
/**
@notice
@notice
The contract storing all funding cycle configurations.
The contract storing all funding cycle configurations.
*/
*/
IJBFundingCycleStore public immutable override fundingCycleStore;
IJBFundingCycleStore public immutable override fundingCycleStore;


/**
/**
@notice
@notice
The contract that manages token minting and burning.
The contract that manages token minting and burning.
*/
*/
IJBTokenStore public immutable override tokenStore;
IJBTokenStore public immutable override tokenStore;


/**
/**
@notice
@notice
The contract that stores splits for each project.
The contract that stores splits for each project.
*/
*/
IJBSplitsStore public immutable override splitsStore;
IJBSplitsStore public immutable override splitsStore;


/**
@notice
A contract that stores fund access constraints for each project.
*/
IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;

/**
/**
@notice
@notice
The directory of terminals and controllers for projects.
The directory of terminals and controllers for projects.
*/
*/
IJBDirectory public immutable override directory;
IJBDirectory public immutable override directory;


//*********************************************************************//
//*********************************************************************//
// ------------------------- external views -------------------------- //
// --------------------- public stored properties -------------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.
The current undistributed reserved token balance of.

@dev
The number of decimals in the returned fixed point amount is the same as that of the specified terminal.

@param _projectId The ID of the project to get the distribution limit of.
@param _configuration The configuration during which the distribution limit applies.
@param _terminal The terminal from which distributions are being limited.
@param _token The token for which the distribution limit applies.

@return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.
@return The currency of the distribution limit.
*/
function distributionLimitOf(
uint256 _projectId,
uint256 _configuration,
IJBPaymentTerminal _terminal,
address _token
) external view override returns (uint256, uint256) {
// Get a reference to the packed data.
uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];

// The limit is in bits 0-231. The currency is in bits 232-255.
return (uint256(uint232(_data)), _data >> 232);
Text moved to lines 248-251
}

/**
@notice
The amount of overflow that a project is allowed to tap into on-demand throughout a configuration, and the currency it's in terms of.

@dev
The number of decimals in the returned fixed point amount is the same as that of the specified terminal.

@param _projectId The ID of the project to get the overflow allowance of.
@param _configuration The configuration of the during which the allowance applies.
@param _terminal The terminal managing the overflow.
@param _token The token for which the overflow allowance applies.

@return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.
@return The currency of the overflow allowance.
*/
function overflowAllowanceOf(
uint256 _projectId,
uint256 _configuration,
IJBPaymentTerminal _terminal,
address _token
) external view override returns (uint256, uint256) {
// Get a reference to the packed data.
uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];

// The allowance is in bits 0-231. The currency is in bits 232-255.
return (uint256(uint232(_data)), _data >> 232);
}

/**
@notice
Gets the amount of reserved tokens that a project has available to distribute.

@param _projectId The ID of the project to get a reserved token balance of.
@param _reservedRate The reserved rate to use when making the calculation.

@return The current amount of reserved tokens.
*/
function reservedTokenBalanceOf(uint256 _projectId, uint256 _reservedRate)
external
view
override
returns (uint256)
{
return
_reservedTokenAmountFrom(
_processedTokenTrackerOf[_projectId],
_reservedRate,
tokenStore.totalSupplyOf(_projectId)
);
}

/**
@notice
Gets the current total amount of outstanding tokens for a project, given a reserved rate.

@param _projectId The ID of the project to get total outstanding tokens of.
@param _reservedRate The reserved rate to use when making the calculation.


@return The current total amount of outstanding tokens for the project.
_projectId The ID of the project to get a reserved token balance of.
*/
*/
function totalOutstandingTokensOf(uint256 _projectId, uint256 _reservedRate)
mapping(uint256 => uint256) public override reservedTokenBalanceOf;
external
view
override
returns (uint256)
{
// Get the total number of tokens in circulation.
uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);

// Get the number of reserved tokens the project has.
uint256 _reservedTokenAmount = _reservedTokenAmountFrom(
_processedTokenTrackerOf[_projectId],
_reservedRate,
_totalSupply
);


// Add the reserved tokens to the total supply.
//*********************************************************************//
return _totalSupply + _reservedTokenAmount;
// ------------------------- external views -------------------------- //
}
//*********************************************************************//


/**
/**
@notice
@notice
A project's funding cycle for the specified configuration along with its metadata.
A project's funding cycle for the specified configuration along with its metadata.


@param _projectId The ID of the project to which the funding cycle belongs.
@param _projectId The ID of the project to which the funding cycle belongs.
@return fundingCycle The funding cycle.
@return fundingCycle The funding cycle.
@return metadata The funding cycle's metadata.
@return metadata The funding cycle's metadata.
*/
*/
function getFundingCycleOf(uint256 _projectId, uint256 _configuration)
function getFundingCycleOf(uint256 _projectId, uint256 _configuration)
external
external
view
view
override
override
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
{
{
fundingCycle = fundingCycleStore.get(_projectId, _configuration);
fundingCycle = fundingCycleStore.get(_projectId, _configuration);
metadata = fundingCycle.expandMetadata();
metadata = fundingCycle.expandMetadata();
}
}


/**
/**
@notice
@notice
A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.
A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.


@param _projectId The ID of the project to which the funding cycle belongs.
@param _projectId The ID of the project to which the funding cycle belongs.
@return fundingCycle The latest configured funding cycle.
@return fundingCycle The latest configured funding cycle.
@return metadata The latest configured funding cycle's metadata.
@return metadata The latest configured funding cycle's metadata.
@return ballotState The state of the configuration.
@return ballotState The state of the configuration.
*/
*/
function latestConfiguredFundingCycleOf(uint256 _projectId)
function latestConfiguredFundingCycleOf(uint256 _projectId)
external
external
view
view
override
override
returns (
returns (
JBFundingCycle memory fundingCycle,
JBFundingCycle memory fundingCycle,
JBFundingCycleMetadata memory metadata,
JBFundingCycleMetadata memory metadata,
JBBallotState ballotState
JBBallotState ballotState
)
)
{
{
(fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);
(fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);
metadata = fundingCycle.expandMetadata();
metadata = fundingCycle.expandMetadata();
}
}


/**
/**
@notice
@notice
A project's current funding cycle along with its metadata.
A project's current funding cycle along with its metadata.


@param _projectId The ID of the project to which the funding cycle belongs.
@param _projectId The ID of the project to which the funding cycle belongs.
@return fundingCycle The current funding cycle.
@return fundingCycle The current funding cycle.
@return metadata The current funding cycle's metadata.
@return metadata The current funding cycle's metadata.
*/
*/
function currentFundingCycleOf(uint256 _projectId)
function currentFundingCycleOf(uint256 _projectId)
external
external
view
view
override
override
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
{
{
fundingCycle = fundingCycleStore.currentOf(_projectId);
fundingCycle = fundingCycleStore.currentOf(_projectId);
metadata = fundingCycle.expandMetadata();
metadata = fundingCycle.expandMetadata();
}
}


/**
/**
@notice
@notice
A project's queued funding cycle along with its metadata.
A project's queued funding cycle along with its metadata.


@param _projectId The ID of the project to which the funding cycle belongs.
@param _projectId The ID of the project to which the funding cycle belongs.
@return fundingCycle The queued funding cycle.
@return fundingCycle The queued funding cycle.
@return metadata The queued funding cycle's metadata.
@return metadata The queued funding cycle's metadata.
*/
*/
function queuedFundingCycleOf(uint256 _projectId)
function queuedFundingCycleOf(uint256 _projectId)
external
external
view
view
override
override
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)
{
{
fundingCycle = fundingCycleStore.queuedOf(_projectId);
fundingCycle = fundingCycleStore.queuedOf(_projectId);
metadata = fundingCycle.expandMetadata();
metadata = fundingCycle.expandMetadata();
}
}


//*********************************************************************//
//*********************************************************************//
// -------------------------- public views --------------------------- //
// -------------------------- public views --------------------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
Gets the current total amount of outstanding tokens for a project.

@param _projectId The ID of the project to get total outstanding tokens of.

@return The current total amount of outstanding tokens for the project.
*/
function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {
// Add the reserved tokens to the total supply.
return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];
Text moved from lines 168-171
}

/**
@notice
Indicates if this contract adheres to the specified interface.
Indicates if this contract adheres to the specified interface.


@dev
@dev
See {IERC165-supportsInterface}.
See {IERC165-supportsInterface}.


@param _interfaceId The ID of the interface to check for adherance to.
@param _interfaceId The ID of the interface to check for adherance to.
*/
*/
function supportsInterface(bytes4 _interfaceId)
function supportsInterface(bytes4 _interfaceId)
public
public
view
view
virtual
virtual
override(ERC165, IERC165)
override(ERC165, IERC165)
returns (bool)
returns (bool)
{
{
return
return
_interfaceId == type(IJBController).interfaceId ||
_interfaceId == type(IJBController3_1).interfaceId ||
_interfaceId == type(IJBController3_0_1).interfaceId ||
_interfaceId == type(IJBMigratable).interfaceId ||
_interfaceId == type(IJBMigratable).interfaceId ||
_interfaceId == type(IJBOperatable).interfaceId ||
_interfaceId == type(IJBOperatable).interfaceId ||
super.supportsInterface(_interfaceId);
super.supportsInterface(_interfaceId);
}
}


//*********************************************************************//
//*********************************************************************//
// ---------------------------- constructor -------------------------- //
// ---------------------------- constructor -------------------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@param _operatorStore A contract storing operator assignments.
@param _operatorStore A contract storing operator assignments.
@param _projects A contract which mints ERC-721's that represent project ownership and transfers.
@param _projects A contract which mints ERC-721's that represent project ownership and transfers.
@param _directory A contract storing directories of terminals and controllers for each project.
@param _directory A contract storing directories of terminals and controllers for each project.
@param _fundingCycleStore A contract storing all funding cycle configurations.
@param _fundingCycleStore A contract storing all funding cycle configurations.
@param _tokenStore A contract that manages token minting and burning.
@param _tokenStore A contract that manages token minting and burning.
@param _splitsStore A contract that stores splits for each project.
@param _splitsStore A contract that stores splits for each project.
@param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.
*/
*/
constructor(
constructor(
IJBOperatorStore _operatorStore,
IJBOperatorStore _operatorStore,
IJBProjects _projects,
IJBProjects _projects,
IJBDirectory _directory,
IJBDirectory _directory,
IJBFundingCycleStore _fundingCycleStore,
IJBFundingCycleStore _fundingCycleStore,
IJBTokenStore _tokenStore,
IJBTokenStore _tokenStore,
IJBSplitsStore _splitsStore
IJBSplitsStore _splitsStore,
IJBFundAccessConstraintsStore _fundAccessConstraintsStore
) JBOperatable(_operatorStore) {
) JBOperatable(_operatorStore) {
projects = _projects;
projects = _projects;
directory = _directory;
directory = _directory;
fundingCycleStore = _fundingCycleStore;
fundingCycleStore = _fundingCycleStore;
tokenStore = _tokenStore;
tokenStore = _tokenStore;
splitsStore = _splitsStore;
splitsStore = _splitsStore;
fundAccessConstraintsStore = _fundAccessConstraintsStore;
}
}


//*********************************************************************//
//*********************************************************************//
// --------------------- external transactions ----------------------- //
// --------------------- external transactions ----------------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
Creates a project. This will mint an ERC-721 into the specified owner's account, configure a first funding cycle, and set up any splits.
Creates a project. This will mint an ERC-721 into the specified owner's account, configure a first funding cycle, and set up any splits.


@dev
@dev
Each operation within this transaction can be done in sequence separately.
Each operation within this transaction can be done in sequence separately.


@dev
@dev
Anyone can deploy a project on an owner's behalf.
Anyone can deploy a project on an owner's behalf.


@param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.
@param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.
@param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.
@param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.
@param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _groupedSplits An array of splits to set for any number of groups.
@param _groupedSplits An array of splits to set for any number of groups.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _terminals Payment terminals to add for the project.
@param _terminals Payment terminals to add for the project.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.


@return projectId The ID of the project.
@return projectId The ID of the project.
*/
*/
function launchProjectFor(
function launchProjectFor(
address _owner,
address _owner,
JBProjectMetadata calldata _projectMetadata,
JBProjectMetadata calldata _projectMetadata,
JBFundingCycleData calldata _data,
JBFundingCycleData calldata _data,
JBFundingCycleMetadata calldata _metadata,
JBFundingCycleMetadata calldata _metadata,
uint256 _mustStartAtOrAfter,
uint256 _mustStartAtOrAfter,
JBGroupedSplits[] calldata _groupedSplits,
JBGroupedSplits[] calldata _groupedSplits,
JBFundAccessConstraints[] calldata _fundAccessConstraints,
JBFundAccessConstraints[] calldata _fundAccessConstraints,
IJBPaymentTerminal[] memory _terminals,
IJBPaymentTerminal[] memory _terminals,
string memory _memo
string memory _memo
) external virtual override returns (uint256 projectId) {
) external virtual override returns (uint256 projectId) {
// Keep a reference to the directory.
// Keep a reference to the directory.
IJBDirectory _directory = directory;
IJBDirectory _directory = directory;


// Mint the project into the wallet of the owner.
// Mint the project into the wallet of the owner.
projectId = projects.createFor(_owner, _projectMetadata);
projectId = projects.createFor(_owner, _projectMetadata);


// Set this contract as the project's controller in the directory.
// Set this contract as the project's controller in the directory.
_directory.setControllerOf(projectId, address(this));
_directory.setControllerOf(projectId, address(this));


// Configure the first funding cycle.
// Configure the first funding cycle.
uint256 _configuration = _configure(
uint256 _configuration = _configure(
projectId,
projectId,
_data,
_data,
_metadata,
_metadata,
_mustStartAtOrAfter,
_mustStartAtOrAfter,
_groupedSplits,
_groupedSplits,
_fundAccessConstraints
_fundAccessConstraints
);
);


// Add the provided terminals to the list of terminals.
// Add the provided terminals to the list of terminals.
if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);
if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);


emit LaunchProject(_configuration, projectId, _memo, msg.sender);
emit LaunchProject(_configuration, projectId, _memo, msg.sender);
}
}


/**
/**
@notice
@notice
Creates a funding cycle for an already existing project ERC-721.
Creates a funding cycle for an already existing project ERC-721.


@dev
@dev
Each operation within this transaction can be done in sequence separately.
Each operation within this transaction can be done in sequence separately.


@dev
@dev
Only a project owner or operator can launch its funding cycles.
Only a project owner or operator can launch its funding cycles.


@param _projectId The ID of the project to launch funding cycles for.
@param _projectId The ID of the project to launch funding cycles for.
@param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _groupedSplits An array of splits to set for any number of groups.
@param _groupedSplits An array of splits to set for any number of groups.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _terminals Payment terminals to add for the project.
@param _terminals Payment terminals to add for the project.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.


@return configuration The configuration of the funding cycle that was successfully created.
@return configuration The configuration of the funding cycle that was successfully created.
*/
*/
function launchFundingCyclesFor(
function launchFundingCyclesFor(
uint256 _projectId,
uint256 _projectId,
JBFundingCycleData calldata _data,
JBFundingCycleData calldata _data,
JBFundingCycleMetadata calldata _metadata,
JBFundingCycleMetadata calldata _metadata,
uint256 _mustStartAtOrAfter,
uint256 _mustStartAtOrAfter,
JBGroupedSplits[] calldata _groupedSplits,
JBGroupedSplits[] calldata _groupedSplits,
JBFundAccessConstraints[] memory _fundAccessConstraints,
JBFundAccessConstraints[] memory _fundAccessConstraints,
IJBPaymentTerminal[] memory _terminals,
IJBPaymentTerminal[] memory _terminals,
string memory _memo
string memory _memo
)
)
external
external
virtual
virtual
override
override
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)
returns (uint256 configuration)
returns (uint256 configuration)
{
{
// If there is a previous configuration, reconfigureFundingCyclesOf should be called instead
// If there is a previous configuration, reconfigureFundingCyclesOf should be called instead
if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)
if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)
revert FUNDING_CYCLE_ALREADY_LAUNCHED();
revert FUNDING_CYCLE_ALREADY_LAUNCHED();


// Set this contract as the project's controller in the directory.
// Set this contract as the project's controller in the directory.
directory.setControllerOf(_projectId, address(this));
directory.setControllerOf(_projectId, address(this));


// Configure the first funding cycle.
// Configure the first funding cycle.
configuration = _configure(
configuration = _configure(
_projectId,
_projectId,
_data,
_data,
_metadata,
_metadata,
_mustStartAtOrAfter,
_mustStartAtOrAfter,
_groupedSplits,
_groupedSplits,
_fundAccessConstraints
_fundAccessConstraints
);
);


// Add the provided terminals to the list of terminals.
// Add the provided terminals to the list of terminals.
if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);
if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);


emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);
emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);
}
}


/**
/**
@notice
@notice
Proposes a configuration of a subsequent funding cycle that will take effect once the current one expires if it is approved by the current funding cycle's ballot.
Proposes a configuration of a subsequent funding cycle that will take effect once the current one expires if it is approved by the current funding cycle's ballot.


@dev
@dev
Only a project's owner or a designated operator can configure its funding cycles.
Only a project's owner or a designated operator can configure its funding cycles.


@param _projectId The ID of the project whose funding cycles are being reconfigured.
@param _projectId The ID of the project whose funding cycles are being reconfigured.
@param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _groupedSplits An array of splits to set for any number of groups.
@param _groupedSplits An array of splits to set for any number of groups.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal. The `_distributionLimit` and `_overflowAllowance` parameters must fit in a `uint232`.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.


@return configuration The configuration of the funding cycle that was successfully reconfigured.
@return configuration The configuration of the funding cycle that was successfully reconfigured.
*/
*/
function reconfigureFundingCyclesOf(
function reconfigureFundingCyclesOf(
uint256 _projectId,
uint256 _projectId,
JBFundingCycleData calldata _data,
JBFundingCycleData calldata _data,
JBFundingCycleMetadata calldata _metadata,
JBFundingCycleMetadata calldata _metadata,
uint256 _mustStartAtOrAfter,
uint256 _mustStartAtOrAfter,
JBGroupedSplits[] calldata _groupedSplits,
JBGroupedSplits[] calldata _groupedSplits,
JBFundAccessConstraints[] calldata _fundAccessConstraints,
JBFundAccessConstraints[] calldata _fundAccessConstraints,
string calldata _memo
string calldata _memo
)
)
external
external
virtual
virtual
override
override
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)
returns (uint256 configuration)
returns (uint256 configuration)
{
{
// Configure the next funding cycle.
// Configure the next funding cycle.
configuration = _configure(
configuration = _configure(
_projectId,
_projectId,
_data,
_data,
_metadata,
_metadata,
_mustStartAtOrAfter,
_mustStartAtOrAfter,
_groupedSplits,
_groupedSplits,
_fundAccessConstraints
_fundAccessConstraints
);
);


emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);
emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);
}
}


/**
/**
@notice
@notice
Mint new token supply into an account, and optionally reserve a supply to be distributed according to the project's current funding cycle configuration.
Mint new token supply into an account, and optionally reserve a supply to be distributed according to the project's current funding cycle configuration.


@dev
@dev
Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.
Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.


@param _projectId The ID of the project to which the tokens being minted belong.
@param _projectId The ID of the project to which the tokens being minted belong.
@param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.
@param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.
@param _beneficiary The account that the tokens are being minted for.
@param _beneficiary The account that the tokens are being minted for.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.
@param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.
@param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.
@param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.
@param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.


@return beneficiaryTokenCount The amount of tokens minted for the beneficiary.
@return beneficiaryTokenCount The amount of tokens minted for the beneficiary.
*/
*/
function mintTokensOf(
function mintTokensOf(
uint256 _projectId,
uint256 _projectId,
uint256 _tokenCount,
uint256 _tokenCount,
address _beneficiary,
address _beneficiary,
string calldata _memo,
string calldata _memo,
bool _preferClaimedTokens,
bool _preferClaimedTokens,
bool _useReservedRate
bool _useReservedRate
) external virtual override returns (uint256 beneficiaryTokenCount) {
) external virtual override returns (uint256 beneficiaryTokenCount) {
// There should be tokens to mint.
// There should be tokens to mint.
if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();
if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();


// Define variables that will be needed outside scoped section below.
// Define variables that will be needed outside scoped section below.
// Keep a reference to the reserved rate to use
// Keep a reference to the reserved rate to use
uint256 _reservedRate;
uint256 _reservedRate;


// Scoped section prevents stack too deep. `_fundingCycle` only used within scope.
// Scoped section prevents stack too deep. `_fundingCycle` only used within scope.
{
{
// Get a reference to the project's current funding cycle.
// Get a reference to the project's current funding cycle.
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);


// Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source
// Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source
_requirePermissionAllowingOverride(
_requirePermissionAllowingOverride(
projects.ownerOf(_projectId),
projects.ownerOf(_projectId),
_projectId,
_projectId,
JBOperations.MINT,
JBOperations.MINT,
directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||
directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||
msg.sender == address(_fundingCycle.dataSource())
msg.sender == address(_fundingCycle.dataSource())
);
);


// If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.
// If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.
if (
if (
!_fundingCycle.mintingAllowed() &&
!_fundingCycle.mintingAllowed() &&
!directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&
!directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&
msg.sender != address(_fundingCycle.dataSource())
msg.sender != address(_fundingCycle.dataSource())
) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();
) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();


// Determine the reserved rate to use.
// Determine the reserved rate to use.
_reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;
_reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;


// Override the claimed token preference with the funding cycle value.
// Override the claimed token preference with the funding cycle value.
_preferClaimedTokens = _preferClaimedTokens == true
_preferClaimedTokens = _preferClaimedTokens == true
? _preferClaimedTokens
? _preferClaimedTokens
: _fundingCycle.preferClaimedTokenOverride();
: _fundingCycle.preferClaimedTokenOverride();
}
}


if (_reservedRate == JBConstants.MAX_RESERVED_RATE)
if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {
// Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.
_processedTokenTrackerOf[_projectId] =
_processedTokenTrackerOf[_projectId] -
SafeCast.toInt256(_tokenCount);
else {
// The unreserved token count that will be minted for the beneficiary.
// The unreserved token count that will be minted for the beneficiary.
beneficiaryTokenCount = PRBMath.mulDiv(
beneficiaryTokenCount = PRBMath.mulDiv(
_tokenCount,
_tokenCount,
JBConstants.MAX_RESERVED_RATE - _reservedRate,
JBConstants.MAX_RESERVED_RATE - _reservedRate,
JBConstants.MAX_RESERVED_RATE
JBConstants.MAX_RESERVED_RATE
);
);

if (_reservedRate == 0)
// If there's no reserved rate, increment the tracker with the newly minted tokens.
_processedTokenTrackerOf[_projectId] =
_processedTokenTrackerOf[_projectId] +
SafeCast.toInt256(beneficiaryTokenCount);


// Mint the tokens.
// Mint the tokens.
tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);
tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);
}
}


// Add reserved tokens if needed
if (_reservedRate > 0)
reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;

emit MintTokens(
emit MintTokens(
_beneficiary,
_beneficiary,
_projectId,
_projectId,
_tokenCount,
_tokenCount,
beneficiaryTokenCount,
beneficiaryTokenCount,
_memo,
_memo,
_reservedRate,
_reservedRate,
msg.sender
msg.sender
);
);
}
}


/**
/**
@notice
@notice
Burns a token holder's supply.
Burns a token holder's supply.


@dev
@dev
Only a token's holder, a designated operator, or a project's terminal can burn it.
Only a token's holder, a designated operator, or a project's terminal can burn it.


@param _holder The account that is having its tokens burned.
@param _holder The account that is having its tokens burned.
@param _projectId The ID of the project to which the tokens being burned belong.
@param _projectId The ID of the project to which the tokens being burned belong.
@param _tokenCount The number of tokens to burn.
@param _tokenCount The number of tokens to burn.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.
@param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.
@param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.
*/
*/
function burnTokensOf(
function burnTokensOf(
address _holder,
address _holder,
uint256 _projectId,
uint256 _projectId,
uint256 _tokenCount,
uint256 _tokenCount,
string calldata _memo,
string calldata _memo,
bool _preferClaimedTokens
bool _preferClaimedTokens
)
)
external
external
virtual
virtual
override
override
requirePermissionAllowingOverride(
requirePermissionAllowingOverride(
_holder,
_holder,
_projectId,
_projectId,
JBOperations.BURN,
JBOperations.BURN,
directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
)
)
{
{
// There should be tokens to burn
// There should be tokens to burn
if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();
if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();


// Get a reference to the project's current funding cycle.
// Get a reference to the project's current funding cycle.
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);


// If the message sender is a terminal, the current funding cycle must not be paused.
// If the message sender is a terminal, the current funding cycle must not be paused.
if (
if (
_fundingCycle.burnPaused() &&
_fundingCycle.burnPaused() &&
!directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
!directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();
) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();


// Update the token tracker so that reserved tokens will still be correctly mintable.
_processedTokenTrackerOf[_projectId] =
_processedTokenTrackerOf[_projectId] -
SafeCast.toInt256(_tokenCount);

// Burn the tokens.
// Burn the tokens.
tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);
tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);


emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);
emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);
}
}


/**
/**
@notice
@notice
Distributes all outstanding reserved tokens for a project.
Distributes all outstanding reserved tokens for a project.


@param _projectId The ID of the project to which the reserved tokens belong.
@param _projectId The ID of the project to which the reserved tokens belong.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.


@return The amount of minted reserved tokens.
@return The amount of minted reserved tokens.
*/
*/
function distributeReservedTokensOf(uint256 _projectId, string calldata _memo)
function distributeReservedTokensOf(uint256 _projectId, string calldata _memo)
external
external
virtual
virtual
override
override
returns (uint256)
returns (uint256)
{
{
return _distributeReservedTokensOf(_projectId, _memo);
return _distributeReservedTokensOf(_projectId, _memo);
}
}


/**
/**
@notice
@notice
Allows other controllers to signal to this one that a migration is expected for the specified project.
Allows other controllers to signal to this one that a migration is expected for the specified project.


@dev
@dev
This controller should not yet be the project's controller.
This controller should not yet be the project's controller.


@param _projectId The ID of the project that will be migrated to this controller.
@param _projectId The ID of the project that will be migrated to this controller.
@param _from The controller being migrated from.
@param _from The controller being migrated from.
*/
*/
function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {
function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {
// This controller must not be the project's current controller.
_projectId; // Prevents unused var compiler and natspec complaints.
if (directory.controllerOf(_projectId) == address(this))
_from; // Prevents unused var compiler and natspec complaints.
revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();

// Set the tracker as the total supply.
_processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));

emit PrepMigration(_projectId, _from, msg.sender);
}
}


/**
/**
@notice
@notice
Allows a project to migrate from this controller to another.
Allows a project to migrate from this controller to another.


@dev
@dev
Only a project's owner or a designated operator can migrate it.
Only a project's owner or a designated operator can migrate it.


@param _projectId The ID of the project that will be migrated from this controller.
@param _projectId The ID of the project that will be migrated from this controller.
@param _to The controller to which the project is migrating.
@param _to The controller to which the project is migrating.
*/
*/
function migrate(uint256 _projectId, IJBMigratable _to)
function migrate(uint256 _projectId, IJBMigratable _to)
external
external
virtual
virtual
override
override
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)
{
{
// Keep a reference to the directory.
// Keep a reference to the directory.
IJBDirectory _directory = directory;
IJBDirectory _directory = directory;


// This controller must be the project's current controller.
// This controller must be the project's current controller.
if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();
if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();


// Get a reference to the project's current funding cycle.
// Get a reference to the project's current funding cycle.
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);


// Migration must be allowed.
// Migration must be allowed.
if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();
if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();


// All reserved tokens must be minted before migrating.
// All reserved tokens must be minted before migrating.
if (
if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');
_processedTokenTrackerOf[_projectId] < 0 ||
uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)
) _distributeReservedTokensOf(_projectId, '');


// Make sure the new controller is prepped for the migration.
// Make sure the new controller is prepped for the migration.
_to.prepForMigrationOf(_projectId, address(this));
_to.prepForMigrationOf(_projectId, address(this));


// Set the new controller.
// Set the new controller.
_directory.setControllerOf(_projectId, address(_to));
_directory.setControllerOf(_projectId, address(_to));


emit Migrate(_projectId, _to, msg.sender);
emit Migrate(_projectId, _to, msg.sender);
}
}


//*********************************************************************//
//*********************************************************************//
// ------------------------ internal functions ----------------------- //
// ------------------------ internal functions ----------------------- //
//*********************************************************************//
//*********************************************************************//


/**
/**
@notice
@notice
Distributes all outstanding reserved tokens for a project.
Distributes all outstanding reserved tokens for a project.


@param _projectId The ID of the project to which the reserved tokens belong.
@param _projectId The ID of the project to which the reserved tokens belong.
@param _memo A memo to pass along to the emitted event.
@param _memo A memo to pass along to the emitted event.


@return tokenCount The amount of minted reserved tokens.
@return tokenCount The amount of minted reserved tokens.
*/
*/
function _distributeReservedTokensOf(uint256 _projectId, string memory _memo)
function _distributeReservedTokensOf(uint256 _projectId, string memory _memo)
internal
internal
returns (uint256 tokenCount)
returns (uint256 tokenCount)
{
{
// Keep a reference to the token store.
// Keep a reference to the token store.
IJBTokenStore _tokenStore = tokenStore;
IJBTokenStore _tokenStore = tokenStore;


// Get the current funding cycle to read the reserved rate from.
// Get the current funding cycle to read the reserved rate from.
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);


// Get a reference to new total supply of tokens before minting reserved tokens.
uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);

// Get a reference to the number of tokens that need to be minted.
// Get a reference to the number of tokens that need to be minted.
tokenCount = _reservedTokenAmountFrom(
tokenCount = reservedTokenBalanceOf[_projectId];
_processedTokenTrackerOf[_projectId],
_fundingCycle.reservedRate(),
_totalTokens
);


// Set the tracker to be the new total supply.
// Reset the reserved token balance
_processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);
reservedTokenBalanceOf[_projectId] = 0;


// Get a reference to the project owner.
// Get a reference to the project owner.
address _owner = projects.ownerOf(_projectId);
address _owner = projects.ownerOf(_projectId);


// Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.
// Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.
uint256 _leftoverTokenCount = tokenCount == 0
uint256 _leftoverTokenCount = tokenCount == 0
? 0
? 0
: _distributeToReservedTokenSplitsOf(
: _distributeToReservedTokenSplitsOf(
_projectId,
_projectId,
_fundingCycle.configuration,
_fundingCycle.configuration,
JBSplitsGroups.RESERVED_TOKENS,
JBSplitsGroups.RESERVED_TOKENS,
tokenCount
tokenCount
);
);


// Mint any leftover tokens to the project owner.
// Mint any leftover tokens to the project owner.
if (_leftoverTokenCount > 0)
if (_leftoverTokenCount > 0)
_tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);
_tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);


emit DistributeReservedTokens(
emit DistributeReservedTokens(
_fundingCycle.configuration,
_fundingCycle.configuration,
_fundingCycle.number,
_fundingCycle.number,
_projectId,
_projectId,
_owner,
_owner,
tokenCount,
tokenCount,
_leftoverTokenCount,
_leftoverTokenCount,
_memo,
_memo,
msg.sender
msg.sender
);
);
}
}


/**
/**
@notice
@notice
Distribute tokens to the splits according to the specified funding cycle configuration.
Distribute tokens to the splits according to the specified funding cycle configuration.


@param _projectId The ID of the project for which reserved token splits are being distributed.
@param _projectId The ID of the project for which reserved token splits are being distributed.
@param _domain The domain of the splits to distribute the reserved tokens between.
@param _domain The domain of the splits to distribute the reserved tokens between.
@param _group The group of the splits to distribute the reserved tokens between.
@param _group The group of the splits to distribute the reserved tokens between.
@param _amount The total amount of tokens to mint.
@param _amount The total amount of tokens to mint.


@return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.
@return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.
*/
*/
function _distributeToReservedTokenSplitsOf(
function _distributeToReservedTokenSplitsOf(
uint256 _projectId,
uint256 _projectId,
uint256 _domain,
uint256 _domain,
uint256 _group,
uint256 _group,
uint256 _amount
uint256 _amount
) internal returns (uint256 leftoverAmount) {
) internal returns (uint256 leftoverAmount) {
// Keep a reference to the token store.
// Keep a reference to the token store.
IJBTokenStore _tokenStore = tokenStore;
IJBTokenStore _tokenStore = tokenStore;


// Set the leftover amount to the initial amount.
// Set the leftover amount to the initial amount.
leftoverAmount = _amount;
leftoverAmount = _amount;


// Get a reference to the project's reserved token splits.
// Get a reference to the project's reserved token splits.
JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);
JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);


//Transfer between all splits.
//Transfer between all splits.
for (uint256 _i; _i < _splits.length; ) {
for (uint256 _i; _i < _splits.length; ) {
// Get a reference to the split being iterated on.
// Get a reference to the split being iterated on.
JBSplit memory _split = _splits[_i];
JBSplit memory _split = _splits[_i];


// The amount to send towards the split.
// The amount to send towards the split.
uint256 _tokenCount = PRBMath.mulDiv(
uint256 _tokenCount = PRBMath.mulDiv(
_amount,
_amount,
_split.percent,
_split.percent,
JBConstants.SPLITS_TOTAL_PERCENT
JBConstants.SPLITS_TOTAL_PERCENT
);
);


// Mints tokens for the split if needed.
// Mints tokens for the split if needed.
if (_tokenCount > 0) {
if (_tokenCount > 0) {
_tokenStore.mintFor(
_tokenStore.mintFor(
// If an allocator is set in the splits, set it as the beneficiary.
// If an allocator is set in the splits, set it as the beneficiary.
// Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.
// Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.
// If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.
// If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.
_split.allocator != IJBSplitAllocator(address(0))
_split.allocator != IJBSplitAllocator(address(0))
? address(_split.allocator)
? address(_split.allocator)
: _split.projectId != 0
: _split.projectId != 0
? projects.ownerOf(_split.projectId)
? projects.ownerOf(_split.projectId)
: _split.beneficiary != address(0)
: _split.beneficiary != address(0)
? _split.beneficiary
? _split.beneficiary
: msg.sender,
: msg.sender,
_projectId,
_projectId,
_tokenCount,
_tokenCount,
_split.preferClaimed
_split.preferClaimed
);
);


// If there's an allocator set, trigger its `allocate` function.
// If there's an allocator set, trigger its `allocate` function.
if (_split.allocator != IJBSplitAllocator(address(0)))
if (_split.allocator != IJBSplitAllocator(address(0)))
_split.allocator.allocate(
_split.allocator.allocate(
JBSplitAllocationData(
JBSplitAllocationData(
address(_tokenStore.tokenOf(_projectId)),
address(_tokenStore.tokenOf(_projectId)),
_tokenCount,
_tokenCount,
18,
18,
_projectId,
_projectId,
_group,
_group,
_split
_split
)
)
);
);


// Subtract from the amount to be sent to the beneficiary.
// Subtract from the amount to be sent to the beneficiary.
leftoverAmount = leftoverAmount - _tokenCount;
leftoverAmount = leftoverAmount - _tokenCount;
}
}


emit DistributeToReservedTokenSplit(
emit DistributeToReservedTokenSplit(
_projectId,
_projectId,
_domain,
_domain,
_group,
_group,
_split,
_split,
_tokenCount,
_tokenCount,
msg.sender
msg.sender
);
);


unchecked {
unchecked {
++_i;
++_i;
}
}
}
}
}
}


/**
/**
@notice
@notice
Configures a funding cycle and stores information pertinent to the configuration.
Configures a funding cycle and stores information pertinent to the configuration.


@param _projectId The ID of the project whose funding cycles are being reconfigured.
@param _projectId The ID of the project whose funding cycles are being reconfigured.
@param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _metadata Metadata specifying the controller specific params that a funding cycle can have. These properties will remain fixed for the duration of the funding cycle.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.
@param _groupedSplits An array of splits to set for any number of groups.
@param _groupedSplits An array of splits to set for any number of groups.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal.
@param _fundAccessConstraints An array containing amounts that a project can use from its treasury for each payment terminal. Amounts are fixed point numbers using the same number of decimals as the accompanying terminal.


@return configuration The configuration of the funding cycle that was successfully reconfigured.
@return configuration The configuration of the funding cycle that was successfully reconfigured.
*/
*/
function _configure(
function _configure(
uint256 _projectId,
uint256 _projectId,
JBFundingCycleData calldata _data,
JBFundingCycleData calldata _data,
JBFundingCycleMetadata calldata _metadata,
JBFundingCycleMetadata calldata _metadata,
uint256 _mustStartAtOrAfter,
uint256 _mustStartAtOrAfter,
JBGroupedSplits[] memory _groupedSplits,
JBGroupedSplits[] memory _groupedSplits,
JBFundAccessConstraints[] memory _fundAccessConstraints
JBFundAccessConstraints[] memory _fundAccessConstraints
) internal returns (uint256) {
) internal returns (uint256) {
// Make sure the provided reserved rate is valid.
// Make sure the provided reserved rate is valid.
if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();
if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();


// Make sure the provided redemption rate is valid.
// Make sure the provided redemption rate is valid.
if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)
if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)
revert INVALID_REDEMPTION_RATE();
revert INVALID_REDEMPTION_RATE();


// Make sure the provided ballot redemption rate is valid.
// Make sure the provided ballot redemption rate is valid.
if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)
if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)
revert INVALID_BALLOT_REDEMPTION_RATE();
revert INVALID_BALLOT_REDEMPTION_RATE();


// Configure the funding cycle's properties.
// Configure the funding cycle's properties.
JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(
JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(
_projectId,
_projectId,
_data,
_data,
JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),
JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),
_mustStartAtOrAfter
_mustStartAtOrAfter
);
);


// Set splits for the group.
// Set splits for the group.
splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);
splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);


// Set distribution limits if there are any.
// Set the funds access constraints.
for (uint256 _i; _i < _fundAccessConstraints.length; ) {
fundAccessConstraintsStore.setFor(
JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];
_projectId,

_fundingCycle.configuration,
// If distribution limit value is larger than 232 bits, revert.
_fundAccessConstraints
if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();
);

// If distribution limit currency value is larger than 24 bits, revert.
if (_constraints.distributionLimitCurrency > type(uint24).max)
revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();

// If overflow allowance value is larger than 232 bits, revert.
if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();

// If overflow allowance currency value is larger than 24 bits, revert.
if (_constraints.overflowAllowanceCurrency > type(uint24).max)
revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();

// Set the distribution limit if there is one.
if (_constraints.distributionLimit > 0)
_packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][
_constraints.terminal
][_constraints.token] =
_constraints.distributionLimit |
(_constraints.distributionLimitCurrency << 232);

// Set the overflow allowance if there is one.
if (_constraints.overflowAllowance > 0)
_packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][
_constraints.terminal
][_constraints.token] =
_constraints.overflowAllowance |
(_constraints.overflowAllowanceCurrency << 232);

emit SetFundAccessConstraints(
_fundingCycle.configuration,
_fundingCycle.number,
_projectId,
_constraints,
msg.sender
);

unchecked {
++_i;
}
}


return _fundingCycle.configuration;
return _fundingCycle.configuration;
}

/**
@notice
Gets the amount of reserved tokens currently tracked for a project given a reserved rate.

@param _processedTokenTracker The tracker to make the calculation with.
@param _reservedRate The reserved rate to use to make the calculation.
@param _totalEligibleTokens The total amount to make the calculation with.

@return amount reserved token amount.
*/
function _reservedTokenAmountFrom(
int256 _processedTokenTracker,
uint256 _reservedRate,
uint256 _totalEligibleTokens
) internal pure returns (uint256) {
// Get a reference to the amount of tokens that are unprocessed.
uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0
? _totalEligibleTokens - uint256(_processedTokenTracker)
: _totalEligibleTokens + uint256(-_processedTokenTracker);

// If there are no unprocessed tokens, return.
if (_unprocessedTokenBalanceOf == 0) return 0;

// If all tokens are reserved, return the full unprocessed amount.
if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;

return
PRBMath.mulDiv(
_unprocessedTokenBalanceOf,
JBConstants.MAX_RESERVED_RATE,
JBConstants.MAX_RESERVED_RATE - _reservedRate
) - _unprocessedTokenBalanceOf;
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
import '@openzeppelin/contracts/utils/math/SafeCast.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import './abstract/JBOperatable.sol';
import './interfaces/IJBController.sol';
import './interfaces/IJBMigratable.sol';
import './interfaces/IJBOperatorStore.sol';
import './interfaces/IJBPaymentTerminal.sol';
import './interfaces/IJBProjects.sol';
import './libraries/JBConstants.sol';
import './libraries/JBFundingCycleMetadataResolver.sol';
import './libraries/JBOperations.sol';
import './libraries/JBSplitsGroups.sol';

/**
@notice
Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.

@dev
Adheres to -
IJBController: General interface for the generic controller methods in this contract that interacts with funding cycles and tokens according to the protocol's rules.
IJBMigratable: Allows migrating to this contract, with a hook called to prepare for the migration.

@dev
Inherits from -
JBOperatable: Several functions in this contract can only be accessed by a project owner, or an address that has been preconfifigured to be an operator of the project.
ERC165: Introspection on interface adherance.
*/
contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {
// A library that parses the packed funding cycle metadata into a more friendly format.
using JBFundingCycleMetadataResolver for JBFundingCycle;

//*********************************************************************//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
import '@openzeppelin/contracts/utils/math/SafeCast.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import './abstract/JBOperatable.sol';
import './interfaces/IJBController3_1.sol';
import './interfaces/IJBMigratable.sol';
import './interfaces/IJBOperatorStore.sol';
import './interfaces/IJBPaymentTerminal.sol';
import './interfaces/IJBProjects.sol';
import './libraries/JBConstants.sol';
import './libraries/JBFundingCycleMetadataResolver.sol';
import './libraries/JBOperations.sol';
import './libraries/JBSplitsGroups.sol';

/**
@notice
Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.

@dev
Adheres to -
IJBController3_1: General interface for the generic controller methods in this contract that interacts with funding cycles and tokens according to the protocol's rules.
IJBMigratable: Allows migrating to this contract, with a hook called to prepare for the migration.

@dev
Inherits from -
JBOperatable: Several functions in this contract can only be accessed by a project owner, or an address that has been preconfifigured to be an operator of the project.
ERC165: Introspection on interface adherance.

@dev
This Controller has the same functionality as JBController3_1, except it is not backwards compatible with the original IJBController view methods.
*/
contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {
// A library that parses the packed funding cycle metadata into a more friendly format.